#include "Game.h"

// SGD Wrappers
#include "../wrappers/CSGD_Direct3D.h"
#include "../wrappers/CSGD_DirectInput.h"
#include "../wrappers/CSGD_TextureManager.h"
#include "../wrappers/CSGD_XAudio2.h"

#include "BitmapFont.h"

#include "IGameState.h"
#include "GameplayState.h"
#include "MainMenuState.h"


#include <cassert>


CGame* CGame::s_Instance = nullptr;


CGame* CGame::GetInstance		( void )
{
	if( s_Instance == nullptr )
		s_Instance = new CGame;

	return s_Instance;
}

void CGame::DeleteInstance	( void )
{
	delete s_Instance;
	s_Instance = nullptr;
}

CGame::CGame(void)
{
	m_pD3D				= nullptr;
	m_pDI				= nullptr;
	m_pTM				= nullptr;
	m_pXA				= nullptr;
	
	m_nScreenWidth		= 1;
	m_nScreenHeight		= 1;
	m_bWindowed			= true;
	m_dwCurrTime		= 0;
	m_fElapsedTime		= 0;
}

CGame::~CGame(void)
{
}

void CGame::Initialize( HWND hWnd, HINSTANCE hInstance, 
					int nScreenWidth, int nScreenHeight,
					bool bWindowed )
{
	m_nScreenWidth		= nScreenWidth;
	m_nScreenHeight		= nScreenHeight;
	m_bWindowed			= bWindowed;


	m_pD3D				= CSGD_Direct3D::GetInstance();
	m_pDI				= CSGD_DirectInput::GetInstance();
	m_pTM				= CSGD_TextureManager::GetInstance();
	m_pXA				= CSGD_XAudio2::GetInstance();

	m_pD3D->InitDirect3D( hWnd, m_nScreenWidth, m_nScreenHeight, m_bWindowed, false );
	m_pDI->InitDirectInput( hWnd, hInstance, DI_KEYBOARD | DI_MOUSE | DI_JOYSTICKS );
	m_pTM->InitTextureManager( m_pD3D->GetDirect3DDevice(), m_pD3D->GetSprite() );
	m_pXA->InitXAudio2();

	//CBitmapFont::GetInstance()->LoadFont( "resources/BitmapFont.xml", "resources/BitmapFont.png" );

	PushState( CMainMenuState::GetInstance() );

	m_dwCurrTime = GetTickCount();
	m_hWnd		 = hWnd;
}

bool CGame::Main( void )
{
	if( m_GameStates.back() == nullptr )
		return false;

	if( Input() == false )
		return false;

	
	if( m_GameStates.back() == nullptr )
		return false;

	Update();
	
	
	if( m_GameStates.back() == nullptr )
		return false;

	Render();

	return true;
}

void CGame::Shutdown( void )
{
	/* Clear states */
	ClearStates();



	m_pXA->ShutdownXAudio2();
	m_pXA = nullptr;

	m_pTM->ShutdownTextureManager();
	m_pTM = nullptr;

	m_pDI->ShutdownDirectInput();
	m_pDI = nullptr;

	m_pD3D->ShutdownDirect3D();
	m_pD3D = nullptr;
}

bool CGame::Input( void )
{
	m_pDI->ReadDevices();

	// Toggle fullscreen
	if( ( m_pDI->KeyDown( DIK_LALT ) || m_pDI->KeyDown( DIK_RALT ) )
		&& m_pDI->KeyDown( DIK_RETURN ) )
	{
		m_bWindowed = !m_bWindowed;
		m_pD3D->ChangeDisplayParam( m_nScreenWidth, m_nScreenHeight, m_bWindowed );
		m_pDI->ClearInput();
	}

	if( m_pDI->KeyDown( DIK_ESCAPE ) && m_pDI->KeyDown( DIK_RETURN ) )
		return false;

	// Let the current state handle input
	//for( size_t i = 0; i < m_GameStates.size(); i++ )
	//	m_GameStates[i]->Input();
	return m_GameStates.back()->Input();
}

void CGame::Update( void )
{
	// Refresh the audio
	m_pXA->Update();


	// Calculate the time elapsed between frames
	DWORD dwNow = GetTickCount();

	m_fElapsedTime = (dwNow - m_dwCurrTime) / 1000.0f;
	
	m_dwCurrTime = dwNow;

	if( m_fElapsedTime >= 0.125f )
		m_fElapsedTime = 0.125f;

	// update the current state
	for( size_t i = 0; i < m_GameStates.size(); i++ )
		m_GameStates[i]->Update( m_fElapsedTime );
}

void CGame::Render( void )
{
	// Clear the background (rgb)
	m_pD3D->Clear( 125,125,125 );

	m_pD3D->DeviceBegin();
	m_pD3D->SpriteBegin();
	{
		// render the current state
		for( size_t i = 0; i < m_GameStates.size(); i++ )
			m_GameStates[i]->Render();

	}
	m_pD3D->SpriteEnd();
	m_pD3D->DeviceEnd();

	// Present the buffer to the screen
	m_pD3D->Present();
}

void CGame::PushState( IGameState* pState )
{
	m_GameStates.push_back( pState );

	if( m_GameStates.back() != nullptr )
		m_GameStates.back()->Enter();

}

void CGame::PopState( void )
{
	if( m_GameStates.back() != nullptr )
		m_GameStates.back()->Exit();


	m_GameStates.pop_back();
}

void CGame::ClearStates( void )
{
	vector< IGameState* >::iterator iter;
	for( iter = m_GameStates.begin(); iter != m_GameStates.end(); ++iter )
	{
		(*iter)->Exit();
	}
	m_GameStates.clear();
}

void CGame::ChangeState( IGameState* pState )
{		
	assert( m_GameStates.size() <= 1 && "NO ChangeState" );
	PopState();
	PushState( pState );
}


